﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Microsoft.Ink;

namespace RozpoznawanieLiter
{
    public class WłaściwościLitery
    {
        char litera;
        double ratio;
        double szerokośćDoWielkościLinii;
        double wysokośćDoWielkościLinii;
        //double środekDoDolnejLinii; //chyba niepotrzebne
        double średniaSzerokośćLitery;
        double średniaWysokośćLitery;
        double najwyższyPunktDoGórnejLinii;
        double najniższyPunktDoDolnejLinii;
        double ilośćPrzecięćZLiniamiPoziomymi; //max 3
        double ilośćPrzecięć; //max 4
        double ilośćPrzerwWPionowymHistogramie; //0 albo 1
        double ilośćMaźnięć; //max 3
        double położenieNajwyższego;
        double położenieNajniższego;
        double położenieNajLewo;
        double położenieNajPrawo;

        Point najwyższy;
        Point najniższy;
        Point najLewo;
        Point najPrawo;

        int szerokość;
        int wysokość;

        Line bl;
        Line ml;
        Line ul;

        public char Litera
        {
            get
            {
                return litera;
            }
            set
            {
                litera = value;
            }
        }

        public double Ratio
        {
            get
            {
                return ratio;
            }
            set
            {
                ratio = value;
            }
        }

        public double SzerokośćDoWielkościLinii
        {
            get
            {
                return szerokośćDoWielkościLinii;
            }
            set
            {
                szerokośćDoWielkościLinii = value;
            }
        }

        public double WysokośćDoWielkościLinii
        {
            get
            {
                return wysokośćDoWielkościLinii;
            }
            set
            {
                wysokośćDoWielkościLinii = value;
            }
        }

        //public double ŚrodekDoDolnejLinii
        //{
        //    get
        //    {
        //        return środekDoDolnejLinii;
        //    }
        //}

        public double ŚredniaSzerokośćLitery
        {
            get
            {
                return średniaSzerokośćLitery;
            }
            set
            {
                średniaSzerokośćLitery = value;
            }
        }

        public double ŚredniaWysokośćLitery
        {
            get
            {
                return średniaWysokośćLitery;
            }
            set
            {
                średniaWysokośćLitery = value;
            }
        }

        public double NajwyższyPunktDoGórnejLinii
        {
            get
            {
                return najwyższyPunktDoGórnejLinii;
            }
            set
            {
                najwyższyPunktDoGórnejLinii = value;
            }
        }

        public double NajniższyPunktDoDolnejLinii
        {
            get
            {
                return najniższyPunktDoDolnejLinii;
            }
            set
            {
                najniższyPunktDoDolnejLinii = value;
            }
        }

        public double IlośćPrzecięćZLiniamiPoziomymi
        {
            get
            {
                return ilośćPrzecięćZLiniamiPoziomymi;
            }
            set
            {
                ilośćPrzecięćZLiniamiPoziomymi = value;
            }
        }

        public double IlośćPrzecięć
        {
            get
            {
                return ilośćPrzecięć;
            }
            set
            {
                ilośćPrzecięć = value;
            }
        }

        public double IlośćPrzerwWPionowymHistogramie
        {
            get
            {
                return ilośćPrzerwWPionowymHistogramie;
            }
            set
            {
                ilośćPrzerwWPionowymHistogramie= value;
            }
        }

        public double IlośćMaźnięć
        {
            get
            {
                return ilośćMaźnięć;
            }
            set
            {
                ilośćMaźnięć = value;
            }
        }

        public double PołożenieNajwyższego
        {
            get
            {
                return położenieNajwyższego;
            }
            set
            {
                położenieNajwyższego = value;
            }
        }

        public double PołożenieNajniższego
        {
            get
            {
                return położenieNajniższego;
            }
            set
            {
                położenieNajniższego = value;
            }
        }

        public double PołożenieNajLewo
        {
            get
            {
                return położenieNajLewo;
            }
            set
            {
                położenieNajLewo = value;
            }
        }

        public double PołożenieNajPrawo
        {
            get
            {
                return położenieNajPrawo;
            }
            set
            {
                położenieNajPrawo = value;
            }
        }

        public WłaściwościLitery(char litera)
        {
            this.litera = litera;
        }

        private void znajdźNajwyższyINajniższy(Strokes maźnięcia)
        {
            najwyższy = new Point();
            najniższy = new Point();
            najLewo = new Point();
            najPrawo = new Point();

            if (maźnięcia.Count > 0)
            {
                najwyższy = maźnięcia[0].GetPoints()[0];
                najniższy = maźnięcia[0].GetPoints()[0];
                najLewo = maźnięcia[0].GetPoints()[0];
                najPrawo = maźnięcia[0].GetPoints()[0];
            }

            foreach (Stroke maźnięcie in maźnięcia)
            {
                foreach (Point p in maźnięcie.GetPoints())
                {
                    if (p.Y < najwyższy.Y)
                        najwyższy = p;
                    if (p.Y > najniższy.Y)
                        najniższy = p;
                    if (p.X > najPrawo.X)
                        najPrawo = p;
                    if (p.X < najLewo.X)
                        najLewo = p;
                }
            }
        }

        public void znajdźRatio(Strokes maźnięcia)
        {
            znajdźNajwyższyINajniższy(maźnięcia);

            szerokość = najPrawo.X - najLewo.X;
            wysokość = najniższy.Y - najwyższy.Y;

            ratio = (double)szerokość / (double)wysokość;

            if (ratio > 1)
                ratio = 1;
        }

        public void znajdźLinie(Strokes maźnięcia)
        {
            Recognizers recs = new Recognizers();
            Recognizer reco = recs.GetDefaultRecognizer();
            RecognizerContext context = reco.CreateRecognizerContext();
            context.Strokes = maźnięcia;
            RecognitionStatus status = RecognitionStatus.NoError;
            RecognitionResult res = context.Recognize(out status);

            bl = res.TopAlternate.Baseline;
            ml = res.TopAlternate.Midline;
            ul = res.TopAlternate.Ascender;
        }

        public void znajdźSzerokośćDoWielkościLinii(Strokes maźnięcia)
        {
            if (bl.BeginPoint.IsEmpty || ml.BeginPoint.IsEmpty || ul.BeginPoint.IsEmpty)
                znajdźLinie(maźnięcia);

            int wysokośćLinii = bl.BeginPoint.Y - ul.BeginPoint.Y;

            szerokośćDoWielkościLinii = (double)szerokość / (double)wysokośćLinii;

            if (szerokośćDoWielkościLinii > 1)
                szerokośćDoWielkościLinii = 1;
        }

        public void znajdźWysokośćDoWielkościLinii(Strokes maźnięcia)
        {
            if (bl.BeginPoint.IsEmpty || ml.BeginPoint.IsEmpty || ul.BeginPoint.IsEmpty)
                znajdźLinie(maźnięcia);

            int wysokośćLinii = bl.BeginPoint.Y - ul.BeginPoint.Y;

            wysokośćDoWielkościLinii = (double)wysokość / (double)wysokośćLinii;

            if (wysokośćDoWielkościLinii > 1)
                wysokośćDoWielkościLinii = 1;
        }

        private Point LocatePoint(Stroke theStroke, float theFIndex)
        {
            // Get the two nearest points to the point of interest.
            Point[] ptStrokePoints = theStroke.GetPoints((int)Math.Floor(theFIndex), 2);

            // Get fractional part to interpolate the distance between the points.
            float theFraction = theFIndex - (float)Math.Floor(theFIndex);

            int deltaX;
            int deltaY;

            if (ptStrokePoints.Length > 1)
            {
                deltaX = (int)((ptStrokePoints[1].X - ptStrokePoints[0].X) * theFraction);
                deltaY = (int)((ptStrokePoints[1].Y - ptStrokePoints[0].Y) * theFraction);
            }
            else
            {
                deltaX = 0;
                deltaY = 0;
            }

            // Return the interpolated point.
            return new Point(ptStrokePoints[0].X + deltaX, ptStrokePoints[0].Y + deltaY);
        }

        public void znajdźŚredniąSzerokośćLitery(InkOverlay collector)
        {
            double szerokości = 0;

            for (int i = 0; i < 20; i++)
            {
                Point[] punkty = { new Point(najLewo.X, najwyższy.Y + (wysokość / 20) * i + 1), new Point(najPrawo.X, najwyższy.Y + (wysokość / 20) * i + 1) };
                Stroke poziomaLinia = collector.Ink.CreateStroke(punkty);
                collector.Ink.Strokes.Add(poziomaLinia);

                float[] przecięcia = poziomaLinia.FindIntersections(collector.Ink.Strokes);

                if (przecięcia.Length > 0)
                {
                    Point pierwszy = LocatePoint(poziomaLinia, przecięcia[0]);
                    Point ostatni = LocatePoint(poziomaLinia, przecięcia[przecięcia.Length - 1]);

                    szerokości += ostatni.X - pierwszy.X;
                }

                collector.Ink.DeleteStroke(poziomaLinia);
            }

            szerokości /= 20;
            średniaSzerokośćLitery = szerokości / (double)szerokość;
        }

        public void znajdźŚredniąWysokośćLitery(InkOverlay collector)
        {
            double wysokości = 0;

            for (int i = 0; i < 20; i++)
            {
                Point[] punkty = { new Point(najLewo.X + (szerokość / 20) * i + 1, najwyższy.Y), new Point(najLewo.X + (szerokość / 20) * i + 1, najniższy.Y) };
                Stroke pionowaLinia = collector.Ink.CreateStroke(punkty);
                collector.Ink.Strokes.Add(pionowaLinia);

                float[] przecięcia = pionowaLinia.FindIntersections(collector.Ink.Strokes);

                if (przecięcia.Length > 0)
                {
                    Point pierwszy = LocatePoint(pionowaLinia, przecięcia[0]);
                    Point ostatni = LocatePoint(pionowaLinia, przecięcia[przecięcia.Length - 1]);

                    wysokości += ostatni.Y - pierwszy.Y;
                }

                collector.Ink.DeleteStroke(pionowaLinia);
            }

            wysokości /= 20;
            średniaWysokośćLitery = wysokości / (double)wysokość;
        }

        public void znajdźNajwyższyPunktDoGórnejLini(Strokes maźnięcia)
        {
            if (bl.BeginPoint.IsEmpty || ml.BeginPoint.IsEmpty || ul.BeginPoint.IsEmpty)
                znajdźLinie(maźnięcia);

            //najwyższyPunktDoGórnejLinii = (double)ul.BeginPoint.Y / (double)najwyższy.Y;

            int odległość = najwyższy.Y - ul.BeginPoint.Y;
            int max = ml.BeginPoint.Y - ul.BeginPoint.Y;

            if (odległość < 0)
                odległość = 0;

            najwyższyPunktDoGórnejLinii = (double)odległość / (double)max;

            if (najwyższyPunktDoGórnejLinii > 1)
                najwyższyPunktDoGórnejLinii = 1;
        }

        public void znajdźNajniższyPunktDoDolnejLini(Strokes maźnięcia)
        {
            if (bl.BeginPoint.IsEmpty || ml.BeginPoint.IsEmpty || ul.BeginPoint.IsEmpty)
                znajdźLinie(maźnięcia);

            //najniższyPunktDoDolnejLinii = (double)bl.BeginPoint.Y / (double)najniższy.Y;

            int odległość = najniższy.Y - bl.BeginPoint.Y;
            int max = bl.BeginPoint.Y - ml.BeginPoint.Y;

            if (odległość < 0)
                odległość = 0;

            najniższyPunktDoDolnejLinii = (double)odległość / (double)max;

            if (najniższyPunktDoDolnejLinii > 1)
                najniższyPunktDoDolnejLinii = 1;
        }

        public void znajdźIlośćPrzecięćZLiniamiPoziomymi(InkOverlay collector)
        {
            double przecięć = 0;

            for (int i = 0; i <= 15; i++)
            {
                Point[] punkty = { new Point(najLewo.X, najwyższy.Y + (wysokość / 15) * i + 1), new Point(najPrawo.X, najwyższy.Y + (wysokość / 15) * i + 1) };
                Stroke poziomaLinia = collector.Ink.CreateStroke(punkty);
                collector.Ink.Strokes.Add(poziomaLinia);

                float[] przecięcia = poziomaLinia.FindIntersections(collector.Ink.Strokes);

                if (przecięcia.Length > 0)
                    przecięć += przecięcia.Length;

                collector.Ink.DeleteStroke(poziomaLinia);
            }

            przecięć /= 15;

            if (przecięć > 3)
                przecięć = 3;

            ilośćPrzecięćZLiniamiPoziomymi = (1.0 / 3.0) * przecięć;
        }

        public void znajdźIlośćPrzecięć(InkOverlay collector)
        {
            List<float> wszystkiePrzecięcia = new List<float>();

            List<int> przecięciueKtóregoMaźnięcia = new List<int>();

            for (int k = 0; k < collector.Ink.Strokes.Count; k++)
            {
                float[] własnePrzecięcia = collector.Ink.Strokes[k].SelfIntersections;
                float[] zewnętrznePrzecięcia = collector.Ink.Strokes[k].FindIntersections(collector.Ink.Strokes);

                if (wszystkiePrzecięcia.Count == 0 && własnePrzecięcia.Length != 0)
                {
                    wszystkiePrzecięcia.Add(własnePrzecięcia[0]);
                    przecięciueKtóregoMaźnięcia.Add(k);
                }

                if (wszystkiePrzecięcia.Count == 0 && zewnętrznePrzecięcia.Length != 0)
                {
                    wszystkiePrzecięcia.Add(zewnętrznePrzecięcia[0]);
                    przecięciueKtóregoMaźnięcia.Add(k);
                }

                foreach (float wp in własnePrzecięcia)
                {
                    for (int i = 0; i < wszystkiePrzecięcia.Count; i++)
                    {
                        Point wpPunkt = LocatePoint(collector.Ink.Strokes[k], wp);
                        Point pPunkt = LocatePoint(collector.Ink.Strokes[przecięciueKtóregoMaźnięcia[i]], wszystkiePrzecięcia[i]);

                        Rectangle hitBox = new Rectangle(wpPunkt.X - 100, wpPunkt.Y - 100, 200, 200);

                        if (!hitBox.Contains(pPunkt) && collector.Ink.Strokes[k].HitTest(pPunkt, 80))
                        {
                            wszystkiePrzecięcia.Add(wp);
                            przecięciueKtóregoMaźnięcia.Add(k);
                        }
                    }
                }

                foreach (float zp in zewnętrznePrzecięcia)
                {
                    for (int i = 0; i < wszystkiePrzecięcia.Count; i++)
                    {
                        Point zpPunkt = LocatePoint(collector.Ink.Strokes[k], zp);
                        Point pPunkt = LocatePoint(collector.Ink.Strokes[przecięciueKtóregoMaźnięcia[i]], wszystkiePrzecięcia[i]);

                        Rectangle hitBox = new Rectangle(zpPunkt.X - 100, zpPunkt.Y - 100, 200, 200);

                        if (!hitBox.Contains(pPunkt) && collector.Ink.Strokes[k].HitTest(pPunkt, 80))
                        {
                            wszystkiePrzecięcia.Add(zp);
                            przecięciueKtóregoMaźnięcia.Add(k);
                        }
                    }
                }
            }

            double ilośćWszystkichPrzecięć = wszystkiePrzecięcia.Count;

            if (ilośćWszystkichPrzecięć > 4)
                ilośćWszystkichPrzecięć = 4;

            ilośćPrzecięć = (1.0 / 4.0) * ilośćWszystkichPrzecięć;
        }

        public void znajdźIlośćMaźnięć(Strokes maźnięcia)
        {
            double ilość = maźnięcia.Count;

            if (ilość > 3)
                ilość = 3;

            ilośćMaźnięć = (1.0 / 3.0) * ilość;
        }

        public void znajdźIlośćPrzerwWPionowymHistogramie(InkOverlay collector)
        {
            int zmiany = 0;

            for (int i = 0; i < 100; i++)
            {
                Point[] punkty = { new Point(najLewo.X, najwyższy.Y + (wysokość / 100) * i + 1), new Point(najPrawo.X, najwyższy.Y + (wysokość / 100) * i + 1) };
                Stroke poziomaLinia = collector.Ink.CreateStroke(punkty);
                collector.Ink.Strokes.Add(poziomaLinia);

                float[] przecięcia = poziomaLinia.FindIntersections(collector.Ink.Strokes);

                if (przecięcia.Length == 0)
                    zmiany++;

                collector.Ink.DeleteStroke(poziomaLinia);
            }

            if (zmiany > 0)
                ilośćPrzerwWPionowymHistogramie = 1;
            else
                ilośćPrzerwWPionowymHistogramie = 0;

            //ilośćPrzerwWPionowymHistogramie = 1;

            //int[] najwyższe = new int[maźnięcia.Count];
            //int[] najniższe = new int[maźnięcia.Count];

            //for (int i = 0; i < maźnięcia.Count; i++)
            //{
            //    Point najwyższyWMaźnięciu = new Point();
            //    Point najniższyWMaźnięciu = new Point();

            //    najwyższyWMaźnięciu = maźnięcia[i].GetPoints()[0];
            //    najniższyWMaźnięciu = maźnięcia[i].GetPoints()[0];

            //    foreach (Point p in maźnięcia[i].GetPoints())
            //    {
            //        if (p.Y < najwyższyWMaźnięciu.Y)
            //            najwyższyWMaźnięciu = p;
            //        if (p.Y > najniższyWMaźnięciu.Y)
            //            najniższyWMaźnięciu = p;
            //    }

            //    najwyższe[i] = najwyższyWMaźnięciu.Y;
            //    najniższe[i] = najniższyWMaźnięciu.Y;
            //}

            //for (int i = 0; i < najniższe.Length; i++)
            //{
            //    for (int j = 0; j < najniższe.Length; j++)
            //    {
            //        if (najwyższe[i] > najwyższe[j] && najniższe[i] < najniższe[j])
            //            ilośćPrzerwWPionowymHistogramie = 0;
            //    }
            //}
        }

        public void znajdźPołożejnieNaj(Strokes maźnięcia)
        {
            int odległość = najwyższy.X - najLewo.X;
            położenieNajwyższego = (double)odległość / (double)szerokość;

            odległość = najniższy.X - najLewo.X;
            położenieNajniższego = (double)odległość / (double)szerokość;

            odległość = najLewo.Y - najwyższy.Y;
            położenieNajLewo = (double)odległość / (double)wysokość;

            odległość = najPrawo.Y - najwyższy.Y;
            położenieNajPrawo = (double)odległość / (double)wysokość;
        }
    }
}
